<?php

namespace pmvc\annotation;

use PHPUnit_Framework_TestCase;
use Exception;
use stdClass;

class Whatever {
	const SOME_CONSTANT = "some constant";
}

class AnnotationParserTest
	extends PHPUnit_Framework_TestCase {

	public function testNextAnnotation() {

		// sample annotation string
		$str = '
		
		/**
		 * This is garbage
		 * @\SomeAnnotation(bool=true, string="test", int=1, float=4.3, annotation=@\Yup(), wtf=1, ints=[1,2 3], x=null)
		 * @\Another()
		 * @\MultiLine(
		 *		x=1,
		 *		wtf=@\WhatWhat(
		 *			var
		 *				=	"in the butt",
		 *			yes=\pmvc\annotation\Whatever::SOME_CONSTANT	)
		 *			, 
		 *		y=420,
		 *		annots=[@\Annot1(),
		 *			@\Annot2(x=1,
		 *				y=[
		 *					1,
		 *					2,
		 *					null,
		 *					[]
		 *				]
		 *			)]
		 *		)
		 */
		 
		 
		';

		// what's expected to be parsed
		$expected1 = $this->createAnnotation("SomeAnnotation");
		$expected1->vars = Array(
			"bool"		=> true,
			"string"	=> "test",
			"int"		=> 1,
			"float"		=> 4.3
		);
		$expected1->vars["annotation"] 	= $this->createAnnotation("Yup");
		$expected1->vars["wtf"]			= 1;
		$expected1->vars["ints"]		= Array(1,2,3);
		$expected1->vars["x"]			= null;

		// what's expected to be parsed
		$expected2 = $this->createAnnotation("Another");

		// what's expected to be parsed
		$expected3 = $this->createAnnotation("MultiLine");
		$expected3->vars["x"]	= 1;
		$expected3->vars["wtf"]	= $this->createAnnotation("WhatWhat", Array("var"=>"in the butt", "yes"=>Whatever::SOME_CONSTANT));
		$expected3->vars["y"]	= 420;
		$expected3->vars["annots"]	= Array($this->createAnnotation("Annot1"), $this->createAnnotation("Annot2", Array("x"=>1,"y"=>Array(1,2,null,Array()))));

		// create lexer
		$lexer = new AnnotationParser($str);

		// assert
		$this->assertEquals($expected1, $lexer->nextAnnotation(), "expected1 doesn't match");
		$this->assertEquals($expected2, $lexer->nextAnnotation(), "expected2 doesn't match");
		$this->assertEquals($expected3, $lexer->nextAnnotation(), "expected3 doesn't match");
		$this->assertFalse($lexer->nextAnnotation(), "Wasn't expecting any more annotations");
		
	}

	public function testNextAnnotation_Arrays() {

		// sample annotation string
		$str = '
		
		/**
		 * This is garbage
		 * @\SomeAnnotation(x=[1,[21, 22, [231, 232], 24], [31, 32], 4])
		 */
		 
		 
		';

		// what's expected to be parsed
		$expected1 = $this->createAnnotation("SomeAnnotation");
		$expected1->vars = Array("x"=>Array(
			1,
			Array(21, 22, Array(231, 232), 24),
			Array(31, 32),
			4
		));
		// create lexer
		$lexer = new AnnotationParser($str);

		// assert
		$this->assertEquals($expected1, $lexer->nextAnnotation(), "expected1 doesn't match");
		$this->assertFalse($lexer->nextAnnotation(), "Wasn't expecting any more annotations");
		
	}

	public function testNextAnnotation_VariableAlreadyDefined() {

		// sample annotation string
		$str = '
		
		/**
		 * This is garbage
		 * @\SomeAnnotation(x=1, x=2)
		 */
		 
		 
		';
		
		// create lexer
		$lexer = new AnnotationParser($str);
		try {
			$lexer->nextAnnotation();
			$this->assertTrue(false, "Expected exception didn't happen");
		} catch(Exception $e) {
			$this->assertEquals("Variable x already defined for SomeAnnotation", $e->getMessage(), "Unexpected exception");
		}
		
	}

	private function createAnnotation($name, $vars=Array()) {
		$ret = new stdClass();
		$ret->name = $name;
		$ret->vars = $vars;
		return $ret;
	}

}

?>